package cn.itcast.p2p20.ui;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/7/29.
 * <p/>
 * 体现封装性
 * 摆放每个子控件之前就要知道每一行有多少个控件，并且知道一行的高度，还要每一行的宽度
 */
public class FlowLayout extends ViewGroup {


    private static final String TAG = "FlowLayout";
    private Line mCurrentLine;

    public FlowLayout(Context context) {
        super(context);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMeasureSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        //测量模式是为指定 mParentGiveMeWidth = 0
        int mParentGiveMeWidth = widthMeasureSpecMode == MeasureSpec.UNSPECIFIED ? Integer.MAX_VALUE : MeasureSpec.getSize(widthMeasureSpec);

        int heightMeasureSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int mParentGiveMeHeight = MeasureSpec.getSize(heightMeasureSpec);

        int maxLineWidth = mParentGiveMeWidth - getPaddingLeft() - getPaddingRight();

        //自己测量的宽度和高度
        int mMeasureWidth = 0;
        int mMeasureHeigth = 0;

        mLines.clear();
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {

            View childView = getChildAt(i);
            if (childView.getVisibility() == GONE) {

                continue;
            }
            measureChild(childView, widthMeasureSpec, heightMeasureSpec);
            //第一行 ， 换行
            if (mCurrentLine == null || !mCurrentLine.canAdddView(childView)) {

                mCurrentLine = new Line(widthMeasureSpecMode == MeasureSpec.EXACTLY, maxLineWidth);
                mLines.add(mCurrentLine);
            }
            mCurrentLine.addView(childView);
        }

        for (Line line : mLines) {

            mMeasureWidth = Math.max(mMeasureWidth, line.usedWidth);
            mMeasureHeigth += line.height;
        }

        mMeasureWidth += getPaddingRight();
        mMeasureHeigth += getPaddingTop() + getPaddingBottom();

        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasureSize(widthMeasureSpecMode, mParentGiveMeWidth, mMeasureWidth),
                getMeasureSize(heightMeasureSpecMode, mParentGiveMeHeight, mMeasureHeigth));
    }

    /**
     * @param measureMode       测量模式
     * @param mParentGiveMeSize 父控件分配给自己的宽度或高度
     * @param mMeasureSize      自己测量的宽度或高度，宽度：每一行子控件累计的最大值， 高度：所有行的高的累加
     * @return
     */
    public int getMeasureSize(int measureMode, int mParentGiveMeSize, int mMeasureSize) {

        if (measureMode == MeasureSpec.EXACTLY) {

            return mParentGiveMeSize;
        } else if (measureMode == MeasureSpec.AT_MOST) {//wrap_content,  就自子控件的宽度或者高度为准但是宽度和高度不能超过父控件做给的宽度和高度

            return Math.min(mParentGiveMeSize, mMeasureSize);
        } else {//UNSPECIFIED

            return mMeasureSize;
        }
    }

    //把一行的子控件封装到这个对象, 每一行子控件的摆放由Line对象自己处理
    private class Line {

        //一行宽度的最大值
        private int maxWidth;
        private boolean widthMeasureModeExactly;

        public Line(boolean widthMeasureModeExactly, int maxWidth) {
            this.widthMeasureModeExactly = widthMeasureModeExactly;
            this.maxWidth = maxWidth;
        }

        private int usedWidth;
        //行高，所有子控件最高的
        public int height;

        private List<View> mViews = new ArrayList<>();


        public boolean canAdddView(View view) {

            MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
            if (usedWidth + view.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin <= maxWidth) {

                return true;
            } else {

                return false;
            }
        }

        public void addView(View view) {

            MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
            mViews.add(view);
            usedWidth += view.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
            height = Math.max(height, view.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin);
        }

        public void layout(int left, int top) {

            int extralWidth = maxWidth - usedWidth;
            int agvWidth = (int) (extralWidth * 1.0 / mViews.size());
            for (View view : mViews) {

                //当宽度空间剩余的时候去平均分配宽度，每个子控件宽度加上agvWidth
                //需要重新测量宽度
                if (widthMeasureModeExactly && agvWidth > 0) {

                    int makeMeasureSpecWidth = MeasureSpec.makeMeasureSpec(view.getMeasuredWidth() + agvWidth, MeasureSpec.EXACTLY);
                    int makeMeasureSpecHeight = MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), MeasureSpec.EXACTLY);
                    //重新测量
                    view.measure(makeMeasureSpecWidth, makeMeasureSpecHeight);
                }
                MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
                int measuredWidth = view.getMeasuredWidth();
                int measuredHeight = view.getMeasuredHeight();
                int l = left + layoutParams.leftMargin;
                int t = (int) (top + /*layoutParams.topMargin*/(height - measuredHeight) * 0.5f);
                int r = l + measuredWidth;
                int b = t + measuredHeight;
                view.layout(l, t, r, b);
                left += measuredWidth + layoutParams.leftMargin + layoutParams.rightMargin;
            }
        }
    }

    private List<Line> mLines = new ArrayList<>();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int left = getPaddingLeft();
        int top = getPaddingTop();
        for (Line line : mLines) {

            //摆放一行
            line.layout(left, top);
            //没摆放一行就加上一行的高度
            top += line.height;
        }
    }


}
